#include<iostream>
#include<string.h>
//#include"ctc_func.h"
#include "ctc_func.h"
#include "ctc_internal.h"
#include<fstream>
#include <limits>
#include <string>
#include <stack>
#include <boost/lexical_cast.hpp>

using namespace CTCFunctions;
//this is the test on the desktop
using namespace std;



static bool gDoCtcTest = false;
static bool gDoRandomGenerator = false;
static bool gDoGraphTest = false;
static const char* author_info = "Author : Xinglong_Gao_Phd@163.com\n";



vector<int> readinSeq(string inputpath)
{
	//int** array= { 0 };
	//int seq[101][490];
	vector<int> v;
	ifstream infile;
	infile.open("ctc-seqs.txt");
	int tmp;
	while (!infile.eof())
	{
		infile >> tmp;
		v.push_back(tmp);
	}
	return v;

}

vector<float> ReadinParams(string inputpath)
{
	vector<float> v;
	ifstream infile;
	infile.open("ctc-params.txt");
	int tmp;
	while (!infile.eof())
	{
		infile >> tmp;
		v.push_back(tmp);
	}
	return v;
}


template<class T> inline void ReadIntegerVector(std::istream &is,
	bool binary,
	std::vector<T> *v) {
	KALDI_ASSERT_IS_INTEGER_TYPE(T);
	if(v != NULL)
		return;
	if (binary) {
		int sz = is.peek();
		if (sz == sizeof(T)) {
			is.get();
		}
		else {  // this is currently just a check.
			std::cerr << "ReadVector: expected to see type of size "
				<< sizeof(T) << ", saw instead " << sz << ", at file position "
				<< is.tellg();
		}
		int vecsz;
		is.read(reinterpret_cast<char *>(&vecsz), sizeof(vecsz));
		if (is.fail() || vecsz < 0) goto bad;
		v->resize(vecsz);
		if (vecsz > 0) {
			is.read(reinterpret_cast<char *>(&((*v)[0])), sizeof(T)*vecsz);
		}
	}
	else {
		std::vector<T> tmp_v;  // use temporary so v doesn't use extra memory
		// due to resizing.
		is >> std::ws;
		if (is.peek() != static_cast<int>('[')) {
			std::cerr << "ReadIntegerVector: expected to see [, saw "
				<< is.peek() << ", at file position " << is.tellg();
		}
		is.get();  // consume the '['.
		is >> std::ws;  // consume whitespace.
		while (is.peek() != static_cast<int>(']')) {
			if (sizeof(T) == 1) {  // read/write chars as numbers.
				short next_t;
				is >> next_t >> std::ws;
				if (is.fail()) goto bad;
				else
					tmp_v.push_back((T)next_t);
			}
			else {
				T next_t;
				is >> next_t >> std::ws;
				if (is.fail()) goto bad;
				else
					tmp_v.push_back(next_t);
			}
		}
		is.get();  // get the final ']'.
		*v = tmp_v;  // could use std::swap to use less temporary memory, but this
		// uses less permanent memory.
	}
	if (!is.fail()) return;
bad:
	std::cerr << "ReadIntegerVector: read failure at file position "
		<< is.tellg();
}


template <typename Elem>
int ReadKaldiVector(const char* vector_txt, std::vector<Elem>& ret_vector){
	if (! vector_txt || ! &ret_vector)
	{
		return -1;
	}
	std::ifstream in_v_fp(vector_txt, ios::in);
	if (in_v_fp.is_open())
	{
		ReadIntegerVector<int>(in_v_fp, false, &ret_vector);
		in_v_fp.close();
	}
}

template <typename Elem>
int ReadPythonMatrix(const char* mat_file, std::vector<std::vector<Elem> >* mat_in){
	int succ_line_num = 0;
	if (mat_in == NULL) return succ_line_num;
	mat_in->resize(1);
	std::ifstream is(mat_file, ios::in);
	if ( ! is.good())
	{
		return succ_line_num;
	}
	is.seekg(0);
	std::vector<Elem> tmp_v;  // use temporary so v doesn't use extra memory
	// due to resizing.
	is >> std::ws;
	if ( is.peek() != static_cast<int>('[')){
		std::cerr << "ReadVector: expected to see [/{, saw "
				<< is.peek() << ", at file position " << is.tellg();
	}
	std::stack<std::string> pair_brackets;
	std::vector<std::string> allelems;
	std::string temp_elem;
	while (! is.eof())
	{
		is >> temp_elem;
		if (temp_elem.compare(",") != 0)
			allelems.push_back(temp_elem);
		temp_elem.clear();
	}
	is.close();
	std::vector<std::string>::const_iterator it = allelems.begin(), end = allelems.end();
	std::vector<Elem> temp_v;
	int vec_num = 0;
	for (; it != end; it++)
	{
		if (it->compare("[") == 0)
		{
			pair_brackets.push(*it);
			continue;
		}
		if (it->compare("]") == 0)
		{
			if (pair_brackets.size()>0)
			{
				if (pair_brackets.top().compare("[") == 0)
				{
					if (temp_v.size() > 0)
					{
						vec_num++;
						if (mat_in->size() < vec_num)
						{
							mat_in->resize(vec_num);
						}
						(*mat_in)[vec_num - 1] = temp_v;
						temp_v.clear();
					}
					pair_brackets.pop();
					continue;
				}
			}
			
		}
		Elem this_elem = boost::lexical_cast<Elem>(*it);
		temp_v.push_back(this_elem);
	}
	return mat_in->size();

}

template <typename Elem>
int CopyMatrix2SimpleArray(const std::vector <std::vector<Elem> >* mat, Elem** simple_mat){
	if (mat->size() == 0)
	{
		return -1;
	}
	std::vector<std::vector<Elem> >::const_iterator it = mat->begin(), end = mat->end();
	int row_ind = 0, col_ind = 0;
	for (; it != end;it++)
	{
		std::vector<Elem>::const_iterator col_it = it->begin(), col_end = it->end();
		for (; col_it != col_end;col_it++)
		{
			simple_mat[row_ind][col_ind] = *col_it;
			col_ind++;
		}
		row_ind++;
	}
	return row_ind*col_ind;
}
//function used to calculate the loss of the CTC
int main(int argc, char* argv[])
{

	std::cout << "CTC Algorithm test...\n";
	std::cout << author_info << std::endl;
	//////////////////////////////////////////////////////////////////////////
	std::string label_file = "labels.txt", feature_file = "features.txt";
	std::string param_matrix_file = "weight.ini";
	FeatureChunk features;
	LabelChunk labels;
	ReadKaldiFeatures(feature_file.c_str(), &features);
	ReadKaldiLabels(label_file.c_str(), &labels);

	DoubleMatrix in_params;
	ReadPythonMatrix<double>(param_matrix_file.c_str(), &in_params);
	int step = 101, seqLen = 490;
	int** seqini2 = new int *[step];
	for (int i = 0; i<step; i++)
	{
		seqini2[i] = new int[seqLen];
		for (int j = 0; j<seqLen; j++)
		{
			seqini2[i][j] = 0;
		}
	}
	vector<int> tmp = readinSeq("a");
	ofstream outf_seq;
	outf_seq.open("ctc-cpp-VecseqAllin.txt", ios::app);
	for (int i = 0; i < 101; i++)
	{
		for (int j = 0; j < 490; j++)
		{
			outf_seq << tmp[i*490+j] << " ,  ";
		}
		outf_seq << endl;
	}
	seqini2 = CopyVector2TwoDimMatrix(step, seqLen, tmp);
	
	outf_seq.open("ctc-cpp-seqAllin.txt", ios::app);
	outf_seq << endl;
	for (int i = 0; i < 101; i++)
	{
		for (int j = 0; j < 490; j++)
		{
			outf_seq << seqini2[i][j] << " ,  ";
		}
		outf_seq << endl;
	}

	std::vector<int> seqinit;
	seqinit.resize(490);
	ReadKaldiVector("seqini2", seqinit);
	int seqini3[490] = { };


	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	
	int array_n=100;
	int array_m=500;
	//int seqLen=9;
	//initialize the seq labels,seq stands for phone level labels
	int *seq;
	//int seqini[490]; 
	//fprintf(stdout, "The length of training sequence is : %d\n", 9);
	//auto stringarray = std::make_shared<std::string>();
	//stringarray->clear();
	
	//initialize the params array_n*array_m
	//but what this params means?
	float **params;
	std::vector<float> init_params = GenerateRandomParams(array_n, array_m);
	
	//vector<float> tmp2 = ReadinParams("a");
	//params = CopyVector2TwoDimMatrix(array_n, array_m, init_params);
	int param_row = 100, param_col = 500;
	double** paramsini = new double*[param_row];
	for (int i = 0; i < param_col;i++)
	{
		paramsini[i] = new double[param_col];
	}
	CopyMatrix2SimpleArray<double>(&in_params, paramsini);

	params=new float*[array_n];
	for(int i=0;i<array_n;i++)
	{
	params[i]=new float[array_m];
	for(int j=0;j<array_m;j++)
	{
	params[i][j]=paramsini[i][j];
	}
	}
	ofstream outf1;
	outf1.open("ctc-params-cpp.txt", ios::app);
	outf1 << endl;
	outf1 << "2017/6/2 Params: " << endl;
	for (int i = 0; i<array_n; i++)
	{
		for (int t = 0; t<array_m; t++)
		{
			outf1 << params[i][t] << ",   ";
		}
		outf1<<endl;
	}
	std::cout << "Parameters have been initialized\n";
	//grad calculating module>
	float **grad;
	//grad calculating module<
	//testing the function ctc loss
	float llforward,llbackward;
	int blank=0;//blank index of phones set
	//std::cout << "Start to calculate ctc loss\n";
	seq = new int[seqLen];
	step = 9;
	for (int cstep = 0; cstep < step; cstep++)
	{
		for (int i = 0; i<seqLen; i++)
		
			seq[i] = tmp[cstep*seqLen+i];
		for (int i = 0; i<array_n; i++)
		{
			
			for (int j = 0; j<array_m; j++)
			{
				params[i][j] = paramsini[i][j];
			}
		}
		llforward = ctc_loss(grad, params, array_n, array_m, seq, seqLen, blank, false);
		
		cout << "the llforward:" << -llforward << endl;

	
		//#######decode procedure#######>
		//cout<<endl;
		//std::vector<int> label_seq;
		//best_path_decode(params, array_n, array_m, label_seq);
		//resultout(grad, array_n, array_m, llforward, cstep, seq, seqLen, params,0);
		//cout << "Best path" << endl;
		//cout << "size:" << label_seq.size() << endl;
	}
	//resultout((float**)seqini2, step, seqLen, llforward, step, seq, seqLen, params,0);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////  No  Loops  ///////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	for (int i = 0; i<seqLen; i++)
//		//seq[i] = seqini2[0][i];
//		seq[i] = seqini3[i];
//	llforward=ctc_loss(grad,params,array_n,array_m,seq,seqLen,blank,false);
//	//cout<<"###########################"<<endl;
//	cout<<"the llforward:"<<-llforward<<endl;
//	//cout<<"###########################"<<endl;
//	//cout<<"the grad calculated  :  "  <<  endl;
//	/*for(int i=0;i<array_n;i++)
//	{
//	for(int t=0;t<array_m;t++)
//	{
//	fprintf(stdout, "u = %d, t = %d, grad[%d][%d] = %f\n", i, t, i, t, grad[i][t]);
//	}
//	cout<<endl;
//	}*/
//	//#######decode procedure#######>
//	//cout<<endl;
//	std::vector<int> label_seq;
//	best_path_decode(params,array_n,array_m,label_seq);
//	resultout(grad, array_n, array_m, llforward, 1, seq,seqLen, params);
//	//cout << "Best path" << endl;
//	//cout << "size:" << label_seq.size() << endl;
////	for(int i=1;i<label_seq.size();i++)
////	std::cout   <<     label_seq[i]   <<   " ";
//	//#######decode procedure#######<
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	delete_bidimen_array(params,array_n,array_m);
	delete [] seq;
	std::cout << "\n\nCTC Test done!\n";
	
	
	return 0;
}
